package ru.xeden.web.html.module;

import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ru.xeden.core.common.ObjectRegistr;
import ru.xeden.core.common.Utils;
import ru.xeden.web.html.component.IComponent;
import ru.xeden.web.html.component.IComponentFactory;
import ru.xeden.web.html.layout.ILayout;
import ru.xeden.web.html.layout.ILayoutFactory;
import ru.xeden.web.html.page.IPage;
import ru.xeden.web.html.page.IPageFactory;
import ru.xeden.web.request.IRequest;


/**
 * Абстрактная реализация модуля
 * @author evga
 *
 */
public abstract class AbstractModule
    implements IModule
{
    private static final Logger LOGGER = LoggerFactory.getLogger(AbstractModule.class);
    
    private IModule parentModule;
    private ObjectRegistr<IModule> subModuleRegistr;
    private IPageFactory pageFactory;
    private IComponentFactory componentFactory;
    private ILayoutFactory layoutFactory;
    private String url;

    public AbstractModule()
    {
        this.subModuleRegistr = new ObjectRegistr<IModule>("register:" + getId());
        this.subModuleRegistr.setComparator(new ModuleComporator());
        LOGGER.debug(String.format("Модуль %s(id:%s) создан", this.getClass().getName(), getId()));
    }

    @Override
    public void setParentModule(IModule parentModule)
    {
        this.parentModule = parentModule;
    }

    @Override
    public IModule getParentModule()
    {
        return this.parentModule;
    }

    @Override
    public boolean registrSubModule(IModule module)
    {
        module.setParentModule(this);
        return subModuleRegistr.register(module);
    }

    @Override
    public boolean unregistrSubModule(IModule module)
    {
        if (subModuleRegistr.unregister(module))
        {
            module.setParentModule(null);
            return true;
        }
        return false;
    }

    @Override
    public List<IModule> getSubModules()
    {
        return subModuleRegistr.getRegisteredObjects();
    }

    @Override
    public void setPageFactory(IPageFactory pageFactory)
    {
        this.pageFactory = pageFactory;
    }

    public void setComponentFactory(IComponentFactory componentFactory)
    {
        this.componentFactory = componentFactory;
    }

    public void setLayoutFactory(ILayoutFactory layoutFactory)
    {
        this.layoutFactory = layoutFactory;
    }

    @Override
    public String getUrl()
    {
        if (url == null)
        {
            synchronized (this)
            {
                if (url == null)
                {
                    IModule p = getParentModule();
                    if (p != null)
                    {
                        url = p.getUrl();
                        url = url == null ? "" : url;
                        if (!Utils.isEmpty(getUrlPiece()))
                        {
                            url = url + "/" + getUrlPiece();
                        }
                    }
                }
            }
        }
        return url;
    }

    @Override
    public IComponent createComponent(String id, Map<String, String> atts)
    {
        IComponent component = null;
        if (componentFactory != null)
        {
            component = componentFactory.createComponent(id, atts);
        }
        if (component == null)
        {
            IModule p = getParentModule();
            if (p != null)
            {
                component = p.createComponent(id, atts);
            }
        }
        return component;
    }

    public ILayout createLayout(String id, IModule leafModule)
    {
        ILayout layout = null;
        if (layoutFactory != null)
        {
            layout = layoutFactory.createLayout(id, leafModule);
        }
        if (layout == null)
        {
            IModule p = getParentModule();
            if (p != null)
            {
                layout = p.createLayout(id, leafModule);
            }
        }
        return layout;
    }

    @Override
    public IPage getPage(IRequest request, UrlPieces pieces)
    {
        String currentPiece = pieces.getCurrentPiece();
        String urlPiece = getUrlPiece();
        if (Utils.isEmpty(urlPiece))
        {
            IPage page = null;
            if (Utils.isEmpty(currentPiece) && pageFactory != null)
            {
                page = pageFactory.createPage(pieces.getPageName(), this);
            }
            return page != null ? page : getFromSubModules(request, pieces);
        }
        else if (urlPiece.equals(currentPiece))
        {
            if (pieces.hasNext())
            {
                pieces.next();
                IPage page = getFromSubModules(request, pieces);
                pieces.previous();
                return page;
            }
            else
            {
                return pageFactory.createPage(pieces.getPageName(), this);
            }
        }
        return null;
    }

    private IPage getFromSubModules(IRequest request, UrlPieces pieces)
    {
        List<IModule> subModules = subModuleRegistr.getRegisteredObjects();
        IPage page = null;
        for (IModule subModule : subModules)
        {
            page = subModule.getPage(request, pieces);
            if (page != null)
            {
                break;
            }
        }
        return page;
    }

    @Override
    public void dispose()
    {
        LOGGER.debug(String.format("Модуль %s(id:%s) диспозен", this.getClass().getName(), getId()));
    }
}
